﻿#pragma once

#include <ctype.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <iostream>


/// @brief 空指针
#define xnullptr nullptr

using xbyte = unsigned char;  ///< 字节类型
using xchar = wchar_t; ///<  C字符串类型, 采用UTF16编码格式. Window系统上是2个字节, Linux系统上是4个字节大小
using xint1 = char; ///< 有符号的1个字节整型
using xuint1 = unsigned char; ///< 无符号的1个字节整型
using xint2 = short; ///< 有符号的2个字节整型
using xuint2 = unsigned short; ///< 无符号的2个字节整型
using xint4 = int; ///< 有符号的4个字节整型
using xuint4 = unsigned int; ///< 无符号的4个字节整型
using xint8 = long long; ///< 有符号的8个字节整型
using xuint8 = unsigned long long; ///< 无符号的8个字节整型
using xint = xint4;   ///< 有符号的4个字节整型, 即zint4类型
using xuint = xuint4; ///< 无符号的4个字节整型, 即zuint4类型
using xlong = long; ///< 有符号的长整型
using xulong = unsigned long; ///< 无符号的长整型
using xfloat4 = float; ///< 浮点类型
using xfloat8 = double; ///< 双精度类型
using xreal = xfloat8; ///< 双精度类型, 既zfloat8类型
using xptr = void *; ///< void* 类型
using xhandle = xptr; ///< 句柄类型
using xsize = xuint8; ///<  采用的大小类型, 即zuint8类型
using xtid = xuint; ///< 线程id, windows/linux 4个字节
/// @brief 时间标准时间(Coordinated Universal Time) 距 1970/01/01 0:0:0 秒数
using xdatetime_t = xint8;

namespace gsrev
{
    static const xsize np = -1;
}

/**
* @brief 日期时间类型\n
* 用于描述年,月,日, 时，分，秒，毫秒,星期
*/
union xdatetime final
{
    /**
    * @brief 是否是闰年
    * @param year [>] 年份
    * @return 返回值说明
    * @retval true 闰年
    * @retval false 平年
    */
    inline static bool isLeapYear(xint8 year) { return (((year % 4) == 0) && ((year % 100) != 0) || (year % 400) == 0); }

    /**
    * @brief 获取月份的天数
    * @param year [>] 年份
    * @param month [>] 月分
    * @return 返回月份的天数
    */
    static xint dayOfMonth(xint8 year, xuint1 month) {
        if (2 == month)
            return isLeapYear(year) ? 29 : 28;

        switch (month)
        {
        case 4:case 6: case 9:case 11:
            return 30;
        default:
            break;
        };

        return 31;
        /*zint day = 30;
        switch (month)
        {
        case 1:case 3: case 5:case 7: case 8: case 10: case 12:
        day = 31;
        break;
        case 2:
        if (isLeapYear(year))
        day = 29;
        else
        day = 28;
        break;
        default:
        break;
        }
        return day;*/
    };

    struct
    {
        xuint2  milliSecond;
        xuint1  second;
        xuint1  minute;
        xuint1  hour;
        xuint1  day;
        xuint1  dayOfWeek;
        xuint1  month;
        xint8   year;  //!< 0表示公元元年, < 0 表示公元前, > 0表示公元后
    };
    /// @cond
    struct
    {
        xuint8 v0;
        xint8  v1;
    };
    xbyte d[16];
    /// @endcond

    xdatetime() : v0(0), v1(0) { dayOfWeek = calcDayOfWeek(0, 0, 0); }

    /// @brief 构造指定日期时间
    /// @param y  [>]年
    /// @param mh [>]月
    /// @param d  [>]日
    /// @param h  [>]时
    /// @param mn [>]分
    /// @param s  [>]秒
    /// @param ms [>]毫秒
    xdatetime(xint8 y, xuint1 mh, xuint1 d, xuint1 h, xuint1 mn, xuint1 s, xuint2 ms) : v0(0), v1(0) {
        year = y;
        month = mh;
        day = d;
        hour = h;
        minute = mn;
        second = s;
        milliSecond = ms;
        dayOfWeek = calcDayOfWeek(y, mh, d);
    }

    /// @cond
    inline bool operator<(const xdatetime & oth) const {
        if (v1 < oth.v1)
            return true;
        if (v1 > oth.v1)
            return false;
        return ((v0 & 0xFF00FFFFFFFFFFFF) < (oth.v0 & 0xFF00FFFFFFFFFFFF));
    }
    inline bool operator>(const xdatetime & oth) const {
        if (v1 > oth.v1)
            return true;
        if (v1 < oth.v1)
            return false;
        return ((v0 & 0xFF00FFFFFFFFFFFF) >(oth.v0 & 0xFF00FFFFFFFFFFFF));
    }
    inline bool operator==(const xdatetime oth) const {
        return (v1 == oth.v1 && ((v0 & 0xFF00FFFFFFFFFFFF) == (oth.v0 & 0xFF00FFFFFFFFFFFF)));
    }
    inline bool operator!=(const xdatetime oth) const {
        return (v1 != oth.v1 || ((v0 & 0xFF00FFFFFFFFFFFF) != (oth.v0 & 0xFF00FFFFFFFFFFFF)));
    }
    inline bool operator<=(const xdatetime & oth) const {
        if (v1 < oth.v1)
            return true;
        if (v1 > oth.v1)
            return false;
        return ((v0 & 0xFF00FFFFFFFFFFFF) <= (oth.v0 & 0xFF00FFFFFFFFFFFF));
    }
    inline bool operator>=(const xdatetime & oth) const {
        if (v1 > oth.v1)
            return true;
        if (v1 < oth.v1)
            return false;
        return ((v0 & 0xFF00FFFFFFFFFFFF) >= (oth.v0 & 0xFF00FFFFFFFFFFFF));
    }
    /// @endcond

    /**@brief 通过年月日计算星期几(蔡勒公式)
    * @param y  [>]年
    * @arg > 0 要求大于0
    * @param mh [>]月
    * @param d  [>]日
    */
    xuint1 calcDayOfWeek(xint8 y, xuint1 mh, xuint1 d) {
        if (mh < 3) {
            y -= 1;
            mh += 12;
        }
        xint8 c = y / 100;
        y = y % 100;
        xint w = (y + y / 4 + c / 4 - 2 * c + (26 * (mh + 1) / 10) + d - 1) % 7;
        if (w < 0)
            w += 7;
        return (xuint1)w;
    }

    /**
    * @brief 是否是闰年
    */
    inline bool isLeapYear() const{ return isLeapYear(year); }

    /**
    * @brief 计算相对给定日期的天数
    * @return 返回计算的天数
    */
    xint8 calcDays(const xdatetime & dt) const
    {
        if (dt.year == year)
        {
            if (dt.month == month)
                return day - dt.day;

            auto calc1 = [](xint8 y, xuint1 m, xuint1 d, xuint1 dm, xuint dd)->xint8
            {
                xint dtmodays = dayOfMonth(y, dm);
                xint8 total = dtmodays - dd;
                for (xint1 i = dm + 1; i < m; ++i)
                    total += dayOfMonth(y, i);

                total += d;
                return total;
            };
            if (month > dt.month)
                return calc1(year, month, day, dt.month, dt.day);

            return -calc1(year, dt.month, dt.day, month, day);
        }

        auto calc2 = [](xint8 y, xuint1 m, xuint1 d, xint8 dy, xuint1 dm, xuint dd)->xint8
        {
            xint dtmodays = dayOfMonth(dy, dm);
            xint total = dtmodays - dd;
            for (xuint1 i = dm + 1; i < 13; ++i)
                total += dayOfMonth(dy, i);

            for (xint8 i = dy + 1; i < y; ++i)
                for (xuint1 j = 1; j < 13; ++j)
                    total += dayOfMonth(i, j);

            for (xuint1 i = 1; i < m; ++i)
                total += dayOfMonth(y, i);

            total += d;
            return total;
        };

        if (year > dt.year)
            return calc2(year, month, day, dt.year, dt.month, dt.day);

        return -calc2(dt.year, dt.month, dt.day, year, month, day);
    }

};

xdatetime x_current_time();

/**@brief 字符返回函数
* @param c [>]字符
* @return 返回输入字符
*/
inline char x_char(char c){ return c; }
inline xchar x_wchar(xchar c){ return c; }

/**@brief 小写字符转大写字符
* @param c [>]转换的字符
* @return 返回大写字符
*/
inline char x_toupper(char c){ return toupper(c); }
inline xchar x_wtoupper(xchar c){ return towupper(c); }

/**@brief 大写字符转小写字符
* @param c [>]转换的字符
* @return 返回大写字符
*/
inline char x_tolower(char c){ return tolower(c); }
inline xchar x_wtolower(xchar c){ return towlower(c); }


template<typename T>
xsize x_str_len(const T * str, const T ce)
{
    if (xnullptr == str)
        return 0;

    xsize len = 0;
    while (ce != *str)
        ++len, ++str;
    return len;
}

template<typename T, typename Fun>
bool x_str_starts_with(const T * str, xsize strLen, const T * cmpstr, xsize cmpstrLen, const T ce, Fun fn)
{
    if (xnullptr == str || xnullptr == cmpstr)
        return false;
    if (str == cmpstr)
        return true;

    if (gsrev::np == strLen)
        strLen = x_str_len(str, ce);
    if (gsrev::np == cmpstrLen)
        cmpstrLen = x_str_len(cmpstr, ce);

    if (cmpstrLen > strLen)
        return false;

    for (xsize i = 0; i < cmpstrLen; ++i)
        if (fn(*(str + i)) != fn(*(cmpstr + i)))
            return false;

    return true;
}

template<typename T, typename Fun>
bool x_str_ends_with(const T * str, xsize strLen, const T * cmpstr, xsize cmpstrLen, const T ce, Fun fn)
{
    if (xnullptr == str || xnullptr == cmpstr)
        return false;
    if (str == cmpstr)
        return true;

    if (gsrev::np == strLen)
        strLen = x_str_len(str, ce);
    if (gsrev::np == cmpstrLen)
        cmpstrLen = x_str_len(cmpstr, ce);

    if (cmpstrLen > strLen)
        return false;

    for (xsize i = cmpstrLen - 1, j = strLen - 1; i != gsrev::np; --i, --j)
        if (fn(*(str + j)) != fn(*(cmpstr + i)))
            return false;

    return true;
}



size_t x_str_utf16_2_ansi(char * buf, xint buf_size, const xchar * wstr);
size_t x_str_ansi_2_utf16(wchar_t * buf, xint buf_size, const char * str);
std::string x_str_replace_all(std::string str, const std::string& from, const std::string& to);
std::string x_str_trim(const std::string & str);
std::wstring x_str_trim(const std::wstring & str);
xint8 x_str_index_of(const char * buf, char c, xint8 from = -1);

std::string x_str_utc(xdatetime_t utc);
std::string x_datetime_to_str(const xdatetime & dt);
bool x_utc_to_datetime(xdatetime_t utc, xdatetime & datetime);

bool x_file_exists(const wchar_t *filename);
bool x_path_exists(const wchar_t * path);

enum OutType
{
    OutType_Unknown,
    OutType_Git,
    OutType_Svn,
    OutType_GitSvn,
    OutType_SvnGit,
};

struct OutFile
{
    OutType outType;
    std::wstring outFile;

    inline bool operator<(const OutFile & o) const {
        return outType < o.outType;
    }

};

xint x_parse_cmdline(
    xint argc, 
    char ** argv, 
    bool &help, 
    std::wstring & path, 
    std::wstring &templateFile, 
    std::vector<OutFile> & outFiles, 
    xint & gH, 
    xint & flag, 
    xint & tortoise,
    xint & hasparams // 是否有参数
    );
bool x_exec_cmd_by_pipe(wchar_t * szFetCmd, const wchar_t * path, char *szBuffer, size_t bufferSize, unsigned long & byteCount);

struct xcodeinfo
{
    /// 类型
    /// -1 表示初始值
    ///  0 表示获取信息失败
    ///  1 表示获取信息成功
    xint result;

    // $XANTVERMGR$
    std::string name;

    //  $XANTLOCALPATH$ 
    std::string localPath;

    /// $XANTCODEPATH$     : git是给的本地路径; svn 是仓储路径
    std::string codePath;

    /// $XANTREVTXT$       : 版本文本格式值, git是SHA-1的值, 如: 9ef7d8f(或9ef7d8f979a52a70ab22f327600c5d8f43309913)默认是短SHA-1取前7个16进制字符; svn是版本号, 如: 21 .
    std::string revTxt;

    /// $XANTREVVAL$          : git是SHA-1值前8个字符的10进制值(短SHA-1值, 参考 http://wiki.xfowks.top:3000/zh/%E7%BC%96%E7%A8%8B/%E7%AC%94%E8%AE%B0/Git); 
    //                       如9ef7d8f979a52a70ab22f327600c5d8f43309913的前7个字符的10进制值 166690191
    //                       svn是svn的版本号
    std::string revVal;

    /// $XANTDATETIME$     : 日期时间
    std::string datetime;

    xcodeinfo()
        : result(-1)
    {}
};

struct xparam
{
    // hash type, 只提供给git命令使用
    // 0 短SHA-1
    // 1 长SHA-1
    xint gH; 

    std::wstring codePath; /// 代码路径

    xparam()
        : gH(0)
    {}
};

xint x_code_git_info(const xparam & pm, xcodeinfo & codeInfo);
xint x_code_svn_info(const xparam & pm, xcodeinfo & codeInfo);


inline const char * x_ant_prefix() { return "gsrev: "; }
inline const wchar_t * x_ant_wprefix() { return L"gsrev: "; }
std::string x_ant_warning_prefix(xint code);
std::wstring x_ant_warning_wprefix(xint code);
std::string x_ant_error_prefix(xint code);
std::wstring x_ant_error_wprefix(xint code);


bool x_out_file(FILE *tmpl, const xcodeinfo & codeInfo, const std::wstring & outFile, const std::string & buildTime, xint tortoise);

// linux 打开文件没有 宽字符 的API函数
FILE* x_wfsopen(const wchar_t* filename, const wchar_t* mode, int _shflag);
FILE* x_popen(const wchar_t* filename, const wchar_t* mode);

xint x_is_dir(const wchar_t * path);